今天繼續以Non-PnP Driver Sample來介紹驅動程式的架構,昨天有提到由WDF所撰寫的驅動程式會有一個DriverEntry
和一些對應特定事件發生時所呼叫的函式,而FileEvtIoDeviceControl
就是針對發生I/O控制要求時所呼叫的函式,部分函式實作如下:
VOID
FileEvtIoDeviceControl(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN size_t OutputBufferLength,
IN size_t InputBufferLength,
IN ULONG IoControlCode
)
/*++
Routine Description:
This event is called when the framework receives IRP_MJ_DEVICE_CONTROL
requests from the system.
Arguments:
Queue - Handle to the framework queue object that is associated
with the I/O request.
Request - Handle to a framework request object.
OutputBufferLength - length of the request's output buffer,
if an output buffer is available.
InputBufferLength - length of the request's input buffer,
if an input buffer is available.
IoControlCode - the driver-defined or system-defined I/O control code
(IOCTL) that is associated with the request.
Return Value:
VOID
--*/
{
NTSTATUS status = STATUS_SUCCESS;// Assume success
PCHAR inBuf = NULL, outBuf = NULL; // pointer to Input and output buffer
PCHAR data = "this String is from Device Driver !!!";
ULONG datalen = (ULONG) strlen(data)+1;//Length of data including null
PCHAR buffer = NULL;
PREQUEST_CONTEXT reqContext = NULL;
size_t bufSize;
UNREFERENCED_PARAMETER( Queue );
PAGED_CODE();
if(!OutputBufferLength || !InputBufferLength)
{
WdfRequestComplete(Request, STATUS_INVALID_PARAMETER);
return;
}
//
// Determine which I/O control code was specified.
//
switch (IoControlCode)
{
case IOCTL_NONPNP_METHOD_BUFFERED:
TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Called IOCTL_NONPNP_METHOD_BUFFERED\n");
//
// For bufffered ioctls WdfRequestRetrieveInputBuffer &
// WdfRequestRetrieveOutputBuffer return the same buffer
// pointer (Irp->AssociatedIrp.SystemBuffer), so read the
// content of the buffer before writing to it.
//
status = WdfRequestRetrieveInputBuffer(Request, 0, &inBuf, &bufSize);
if(!NT_SUCCESS(status)) {
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
ASSERT(bufSize == InputBufferLength);
//
// Read the input buffer content.
// We are using the following function to print characters instead
// TraceEvents with %s format because the string we get may or
// may not be null terminated. The buffer may contain non-printable
// characters also.
//
Hexdump((TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Data from User : %!HEXDUMP!\n",
log_xstr(inBuf, (USHORT)InputBufferLength)));
PrintChars(inBuf, InputBufferLength );
status = WdfRequestRetrieveOutputBuffer(Request, 0, &outBuf, &bufSize);
if(!NT_SUCCESS(status)) {
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
ASSERT(bufSize == OutputBufferLength);
//
// Writing to the buffer over-writes the input buffer content
//
RtlCopyMemory(outBuf, data, OutputBufferLength);
Hexdump((TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Data to User : %!HEXDUMP!\n",
log_xstr(outBuf, (USHORT)datalen)));
PrintChars(outBuf, datalen );
//
// Assign the length of the data copied to IoStatus.Information
// of the request and complete the request.
//
WdfRequestSetInformation(Request,
OutputBufferLength < datalen? OutputBufferLength:datalen);
//
// When the request is completed the content of the SystemBuffer
// is copied to the User output buffer and the SystemBuffer is
// is freed.
//
break;
...
default:
//
// The specified I/O control code is unrecognized by this driver.
//
status = STATUS_INVALID_DEVICE_REQUEST;
TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "ERROR: unrecognized IOCTL %x\n", IoControlCode);
break;
}
TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Completing Request %p with status %X",
Request, status );
WdfRequestComplete( Request, status);
}
FileEvtIoDeviceControl
可以依據傳入的I/O control code執行對應的動作,I/O control code可以為系統宣告或驅動程式自行宣告,若要自行宣告則會使用巨集CTRL_CODE
來處理,格式如下:
#define IOCTL_Device_Function CTL_CODE(DeviceType, FunctionCode, TransferType, RequiredAccess)
DEVICE_OBJECT
結構之DeviceType
成員中所設定的值,小於0x800的值為微軟所保留。METHOD_BUFFERED
METHOD_IN_DIRECT
或METHOD_OUT_DIRECT
METHOD_NEITHER
FILE_ANY_ACCESS
FILE_READ_DATA
FILE_WRITE_DATA
在Non-PnP driver中,有自行宣告I/O control code,位於public.h
,宣告如下,分別對應四種不同的TransferType。
//
// The IOCTL function codes from 0x800 to 0xFFF are for customer use.
//
#define IOCTL_NONPNP_METHOD_IN_DIRECT \
CTL_CODE( FILEIO_TYPE, 0x900, METHOD_IN_DIRECT, FILE_ANY_ACCESS )
#define IOCTL_NONPNP_METHOD_OUT_DIRECT \
CTL_CODE( FILEIO_TYPE, 0x901, METHOD_OUT_DIRECT , FILE_ANY_ACCESS )
#define IOCTL_NONPNP_METHOD_BUFFERED \
CTL_CODE( FILEIO_TYPE, 0x902, METHOD_BUFFERED, FILE_ANY_ACCESS )
#define IOCTL_NONPNP_METHOD_NEITHER \
CTL_CODE( FILEIO_TYPE, 0x903, METHOD_NEITHER , FILE_ANY_ACCESS )
以本次主題要用到驅動程式透過I/O埠與環控晶片溝通,就可以自行定義I/O control code,當驅動程式收到對應的I/O control code,就可以對指定的I/O埠讀取或寫入資料。
Non-PnP Driver Sample
定義 I/O 控制程式碼 - Windows drivers | Microsoft Learn
指定裝置類型 - Windows drivers | Microsoft Learn